package com.gmail.wangzdl.swing.jtable;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class SortManager implements TableModelListener {
	final static Icon upIcon = new UpDownArrow(UpDownArrow.UP);
	final static Icon downIcon = new UpDownArrow(UpDownArrow.DOWN);
	private JTable table;
	private TableModel dataModel;
	private int sortColumn;
	private Row rows[];
	private boolean ascending;
	private int sortableColumns[];

	public SortManager(JTable jtable) {
		rows = null;
		ascending = false;
		sortableColumns = null;
		table = jtable;
		int i = 0;
		int length = jtable.getModel().getColumnCount();
		final int[] columns = new int[length];
		for (; i < length; i++) {
			columns[i] = i;
		}
		sortableColumns = columns;
		initialize();
	}

	public SortManager(JTable jtable, int i) {
		rows = null;
		ascending = false;
		sortableColumns = null;
		table = jtable;
		sortColumn = i;
		initialize();
	}

	public SortManager(JTable jtable, int ai[]) {
		this(jtable, ai[0]);
		sortableColumns = (int[]) ai.clone();
	}

	public void initialize() {
		dataModel = table.getModel();
		((AbstractTableModel) dataModel).addTableModelListener(this);
		addMouseListener(table);
		JTableHeader jtableheader = table.getTableHeader();
		jtableheader.setDefaultRenderer(createHeaderRenderer());
		if (table.getRowCount() > 0) {
			reinitialize();
		}
	}

	protected TableCellRenderer createHeaderRenderer() {
		DefaultTableCellRenderer defaultHeaderRenderer = new SortHeaderRenderer();
		defaultHeaderRenderer.setHorizontalAlignment(0);
		defaultHeaderRenderer.setHorizontalTextPosition(2);
		return defaultHeaderRenderer;
	}

	public void reinitialize() {
		rows = null;
		if (table.getRowCount() > 0) {
			rows = new Row[table.getRowCount()];
			for (int i = 0; i < rows.length; i++) {
				rows[i] = new Row();
				rows[i].index = i;
			}

			if (columnIsSortable(sortColumn)) {
				sort();
			}
		}
	}

	private boolean columnIsSortable(int i) {
		if (rows != null) {
			if (sortableColumns != null) {
				for (int j = 0; j < sortableColumns.length; j++) {
					if (i == sortableColumns[j]) {
						return true;
					}
				}

			} else {
				return true;
			}
		}
		return false;
	}

	public void addMouseListener(final JTable table) {
		table.getTableHeader().addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent mouseevent) {
				int i = table.columnAtPoint(mouseevent.getPoint());
				int j = table.convertColumnIndexToModel(i);
				if (!columnIsSortable(j)) {
					return;
				}
				if (j == sortColumn) {
					ascending = !ascending;
				} else {
					ascending = false;
					sortColumn = j;
				}
				sort();
			}
		});
	}

	public void sort() {
		if (rows == null) {
			return;
		} else {
			((AbstractTableModel) dataModel).removeTableModelListener(this);
			if (!ascending)
				Arrays.sort(rows);
			else {
				Arrays.sort(rows);
				Row temp;
				for (int i = 0; i < rows.length / 2; i++) {
					temp = rows[i];
					rows[i] = rows[rows.length - i - 1];
					rows[rows.length - i - 1] = temp;
				}
			}

			resetData();
			((AbstractTableModel) dataModel).fireTableDataChanged();
			((AbstractTableModel) dataModel).addTableModelListener(this);
			table.revalidate();
			table.repaint();
			return;
		}
	}

	public void resetData() {
		Vector data = new Vector(dataModel.getRowCount());
		int i = 0;
		for (; i < dataModel.getRowCount(); i++) {
			int j = 0;
			final Vector vv = new Vector(dataModel.getColumnCount());
			for (; j < dataModel.getColumnCount(); j++) {
				vv.add(dataModel.getValueAt(i, j));
			}
			data.add(vv);
		}
		i = 0;
		for (; i < rows.length; i++) {
			if (rows[i].index != i) {
				int j = 0;
				final Vector vv = (Vector) data.get(rows[i].index);
				for (; j < dataModel.getColumnCount(); j++) {
					dataModel.setValueAt(vv.get(j), i, j);
				}
			}
		}
	}

	public void tableChanged(TableModelEvent tablemodelevent) {
		reinitialize();
	}

	class SortHeaderRenderer extends DefaultTableCellRenderer {

		public Component getTableCellRendererComponent(JTable jtable,
				Object obj, boolean flag, boolean flag1, int i, int j) {
//			if (jtable != null) {
//				JTableHeader jtableheader = jtable.getTableHeader();
//				if (jtableheader != null) {
//					// setForeground(jtableheader.getForeground());
//					// setBackground(jtableheader.getBackground());
//					// setFont(jtableheader.getFont());
//				}
//			}
			setText(obj != null ? obj.toString() : "");
			int k = jtable.convertColumnIndexToModel(j);
			if (k == sortColumn) {
				setIcon(ascending ? SortManager.upIcon : SortManager.downIcon);
			} else {
				setIcon(new Icon() {
					public int getIconHeight() {
						return 12;
					}
					public int getIconWidth() {
						return 12;
					}
					public void paintIcon(Component arg0, Graphics arg1,
							int arg2, int arg3) {
					}
				});
			}
			// setBorder(UIManager.getBorder(" TableHeader.cellBorder "));
			return this;
		}
	}

	class Row implements Comparable {
		private Row() {
		}

		public int compareTo(Object obj) {
			Row row = (Row) obj;
			java.text.Collator cnCollator = java.text.Collator
					.getInstance(Locale.getDefault());
			Object obj1 = dataModel.getValueAt(index, sortColumn);
			Object obj2 = dataModel.getValueAt(row.index, sortColumn);
			if (ascending) {
				if (!(obj1 instanceof Comparable)) {
					return -1;
				}
				if (!(obj2 instanceof Comparable)) {
					return 1;
				} else {
				}
			}
			if (!(obj1 instanceof Comparable)) {
				return 1;
			}
			if (!(obj2 instanceof Comparable)) {
				return -1;
			} else {
				return cnCollator.compare(obj2, obj1);
			}
		}

		public int index;
	}

	static class UpDownArrow implements Icon {
		private int size = 12;
		public static final int UP = 0;
		public static final int DOWN = 1;
		private int direction;

		public UpDownArrow(int i) {
			direction = i;
		}

		public int getIconHeight() {
			return size;
		}

		public int getIconWidth() {
			return size;
		}

		public void paintIcon(Component component, Graphics g, int x, int y) {	
			int ax = x + 1;
			int ay = (y + size) - 2;
			
			int bx = (x + size) - 2;
			
			int cx = x + size / 2;
			int cy = y + 1;
			
			
			// Color color = (Color) UIManager.get(" controlDkShadow ");
			if (direction == 0) {
				// g.setColor(Color.white);
				// g.setColor(color);
				g.drawLine(ax, ay, bx, ay);
				g.drawLine(bx, ay, cx, cy);
				// g.setColor(color);
				// g.setColor(Color.white);
				g.drawLine(ax, ay, cx, cy);
			} else {
				// g.setColor(color);
				g.drawLine(ax, cy, bx, cy);
				g.drawLine(ax, cy, cx, ay);
				// g.setColor(Color.white);
				g.drawLine(bx, cy, cx, ay);
			}
		}
	}
}